///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef __BUOLA_UTILITY_FORMAT_H__
#define __BUOLA_UTILITY_FORMAT_H__

#include <buola/buola.h>

namespace buola {

///\addtogroup utility
///@{

namespace detail {

template<typename tType>
struct QIsStringView : public std::false_type {};

template<typename tChar>
struct QIsStringView<basic_string_view<tChar>> : public std::true_type {};

template<typename tChar>
basic_string_view<tChar> make_string_view(const basic_string_view<tChar> &pString)
{
    return pString;
}

template<typename tChar>
basic_string_view<tChar> make_string_view(const std::basic_string<tChar> &pString)
{
    return pString;
}

string_view make_string_view(const char *pString)
{
    return pString;
}

template<typename tType>
std::string make_string_view(const tType &pType)
{
    return to_string(pType);
}

/*namespace detail*/ }

template<typename... tArgs>
OEnableIf<QAll<detail::QIsStringView,tArgs...>,std::string> format(const string_view &pFormat,const tArgs&... pArgs)
{
    std::string lRes;
    lRes.reserve(2*pFormat.length());
    string_view lStrings[sizeof...(pArgs)]={pArgs...};
    
    for(auto i=pFormat.begin();i!=pFormat.end();++i)
    {
        if(*i=='%')
        {
            auto b=++i;
            while(true)
            {
                if(i==pFormat.end())
                    throw XInvalid("invalid format string");
                if(*i=='%') break;
                ++i;
            }
            if(i!=b)
            {
                int n=0;
                for(auto j=b;j!=i;j++)
                {
                    n*=10;
                    n+=*j-'0';
                }
                if(n<0||n>=sizeof...(pArgs)) throw XInvalid("invalid argument index in format string");
                lRes.append(lStrings[n].begin(),lStrings[n].end());
                continue;
            }
        }

        lRes+=*i;
    }
    
    return lRes;
}

template<typename... tArgs>
OEnableIfNot<QAll<detail::QIsStringView,tArgs...>,std::string> format(const string_view &pFormat,const tArgs&... pArgs)
{
    return format(pFormat,detail::make_string_view(pArgs)...);
}

///@}

/*namespace buola*/ }

#endif
